package org.kumas.sgrpc.remoting.transport.netty;

import java.io.IOException;
import java.util.List;

import org.kumas.sgrpc.common.URL;
import org.kumas.sgrpc.remoting.Channel;
import org.kumas.sgrpc.remoting.Codec;
import org.kumas.sgrpc.remoting.Codec.DecodeResult;
import org.kumas.sgrpc.remoting.buffer.ChannelBuffer;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;

/**
 *
 * @author KumasZhang
 * @version 1.0
 * @since 2021-07-15 14:15
 */
final public class NettyCodecAdapter {
    private final ChannelHandler encoder = new MessageToByteEncoder() {

        @Override
        protected void encode(ChannelHandlerContext ctx, Object msg,
            ByteBuf byteBuf) throws Exception {
            ChannelBuffer buffer = new NettyBackedChannelBuffer(byteBuf);
            Channel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
            codec.encode(channel, buffer, msg);
        }
    };

    private final ChannelHandler decoder = new ByteToMessageDecoder() {

        @Override
        protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf,
            List<Object> list) throws Exception {
            ChannelBuffer message = new NettyBackedChannelBuffer(byteBuf);
            NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
            do {
                int saveReaderIndex = message.readerIndex();
                Object msg = codec.decode(channel, message);
                if (msg == DecodeResult.NEED_MORE_INPUT) {
                    message.readerIndex(saveReaderIndex);
                    break;
                } else {
                    if (saveReaderIndex == message.readerIndex()) {
                        throw new IOException("Decode without read data.");
                    }

                    if (msg != null) {
                        list.add(msg);
                    }
                }
            } while (message.readable());
        }
    };

    private final Codec codec;

    private final URL url;

    private final org.kumas.sgrpc.remoting.ChannelHandler handler;

    public NettyCodecAdapter(Codec codec, URL url, org.kumas.sgrpc.remoting.ChannelHandler handler) {
        this.codec = codec;
        this.url = url;
        this.handler = handler;
    }

    public ChannelHandler getEncoder() {
        return encoder;
    }

    public ChannelHandler getDecoder() {
        return decoder;
    }


}
